/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
#include <pthread.h>
#include "sle_hilog.h"
#include "common_list.h"
#include "kh_sle_host.h"
#include "kh_sle_connect.h"
#include "kh_sle_ssap_client.h"
#include "kh_sle_ssap_server.h"
#include "sle_dev_ssap_connect.h"
#include "sle_lite_tool_ssap_client.h"
#include "sle_iperf_common.h"
#include "sle_iperf_test_util.h"
#include <time.h>
#include <errno.h>
#include "os_interface.h"

typedef enum {
    SLE_SSAP_CONNECT_STATE_INIT,
    SLE_SSAP_CONNECT_STATE_LINK_DISCONNECTING,
    SLE_SSAP_CONNECT_STATE_LINK_DISCONNECTED,
    SLE_SSAP_CONNECT_STATE_LINK_CONNECTING,
    SLE_SSAP_CONNECT_STATE_LINK_CONNECTED,
    SLE_SSAP_CONNECT_STATE_CONN_PARAM_UPDATING,
    SLE_SSAP_CONNECT_STATE_CONN_PARAM_UPDATED,
    SLE_SSAP_CONNECT_STATE_INFO_EXCHANGING,
    SLE_SSAP_CONNECT_STATE_INFO_EXCHANGED,
    SLE_SSAP_CONNECT_STATE_ERROR,
} SleSsapConnState_t;

typedef enum {
    SLE_SSAP_ROLE_IS_SERVER   = 0,
    SLE_SSAP_ROLE_IS_CLIENT   = 1,
} SleConnSsapRoleType_t;

typedef struct {
    sle_kht_txrx_stat_t ssap_rx_stat; //总数据
    uint64_t recvSumBytes;
    uint64_t recvCostSumMicroseconds;
    uint64_t sle_kht_this_pack_arrive;
    uint64_t sle_kht_last_pack_arrive;
    uint64_t sle_kht_max_jitter;
    uint32_t start_seq;    //开始包
    uint32_t last_seq;     //上一个包
    uint16_t g_SEND_STEP_S_TO_C;
    uint16_t g_ALL_SEND_PACKAGE_S_TO_C;
    uint32_t g_IPERF_TIME_S_TO_C;
    uint16_t g_SLE_KHT_IPERF_ONCE_PACK_NUM_S_TO_C;
    uint32_t g_iperf_long_time_delay_msS_TO_C;
} SleThroughputTestInfo_t; // 测试带宽

typedef struct {
    uint64_t lastSendTime;
    uint64_t oneCycleMinTime;
    uint64_t oneCycleMaxTime;
    uint64_t delayTimeSum;
    uint32_t cycleCount;
    uint64_t endTime;   //microsecond
    uint32_t sendPackageSum;
    uint32_t interval;  //millisecond
} SleLatencyTestInfo_t;

typedef struct {
    uint32_t msgSeqId;
    uint32_t recvSeqId;
    uint32_t lostPkgCountSum;
    uint64_t cycleSendTime;
    uint64_t cycleRecvTime;
    uint64_t cycleRttSum;
    uint64_t cycleLastPrintTime;
    uint32_t cycleLostPkgCount;
    uint32_t cycleSendedPkgCount;
    uint64_t endTime;   //microsecond
    uint32_t sendPackageSum;
    uint32_t interval;  //millisecond
} SleLongTermStabilityTestInfo_t;

typedef struct {
    ListNode node;
    SleSsapConnState_t connState;
    SleConnSsapRoleType_t localRole;
    uint16_t connectId;
    SleDeviceAddress addr;
    SleThroughputTestInfo_t *clientThroughputTestInfo;
    SleThroughputTestInfo_t *serverThroughputTestInfo;
    SleLatencyTestInfo_t *latencyTestInfo;
    SleLongTermStabilityTestInfo_t *ltsTestInfo;
} SleSsapConnectDevNode_t;

typedef enum {
    DATA_FLAG_NO_USE = 0,
    DATA_FLAG_SENDED = 1,
    DATA_FLAG_RECEIVED = 2,
} DataOptFlag_t;

static KHC_mutex_t mkhMutex;
static KHC_cond_t mkhMutexCond;
static pthread_mutex_t g_mutex;
static LIST_HEAD(g_sleSsapConnectList);
static SleConnectionParamUpdateEvt g_sleConnParam = {
    .interval = 22,
    .latency  = 0,
    .supervisionTimeout = 500,
};

extern uint64_t sle_khtest_clock_gettime_us_lite(void);

static char *DoubleToString(double val, char *strBuf, int32_t bufSize)
{
    if (bufSize < 10) {
        return " ";
    }
    memset(strBuf, 0, bufSize);
    uint32_t a = (int32_t)val;
    if (a > 9999) {
        return " ";
    }
    uint32_t b = (val-a)*1000;
    sprintf(strBuf, "%d.%03d", a, b);
    return strBuf;
}

static void DelSsapConnDevNode(SleSsapConnectDevNode_t *item)
{
    CHECK_NULL_PTR_RETURN_VOID(item);
    ListDelete(&item->node);
    SoftBusFree(item);
}

static void ClearSleSsapConnectList(void)
{
    pthread_mutex_lock(&g_mutex);
    SleSsapConnectDevNode_t *item = NULL;
    SleSsapConnectDevNode_t *next = NULL;
    LIST_FOR_EACH_ENTRY_SAFE(item, next, &g_sleSsapConnectList, SleSsapConnectDevNode_t, node) {
        DelSsapConnDevNode(item);
    }
    pthread_mutex_unlock(&g_mutex);
}

static void DeleteSsapConnDevNodeBySleAddr(SleDeviceAddress *addr)
{
    CHECK_NULL_PTR_RETURN_VOID(addr);
    pthread_mutex_lock(&g_mutex);
    SleSsapConnectDevNode_t *item = NULL;
    LIST_FOR_EACH_ENTRY(item, &g_sleSsapConnectList, SleSsapConnectDevNode_t, node) {
        if (0 == memcmp(item->addr.addr, addr, SLE_DEVICE_ADDRESS_LEN)) {
            DelSsapConnDevNode(item);
            break;
        }
    }
    pthread_mutex_unlock(&g_mutex);
}

void UpdateSleConnParamValue(SleConnectionParamUpdateEvt *param)
{
    if (param == NULL) {
        return;
    }
    g_sleConnParam.interval = param->interval;
    g_sleConnParam.latency = param->latency;
    g_sleConnParam.supervisionTimeout = param->supervisionTimeout;
    SLE_LOGI("Success update sle connect param value[.interval= %hu, .latency= %hu, .supervisionTimeout= %hu]", 
                g_sleConnParam.interval, g_sleConnParam.latency, g_sleConnParam.supervisionTimeout);
}

static SleSsapConnectDevNode_t *GetSsapConnNodeByAddr(const SleDeviceAddress *remoteAddr)
{
    if (!remoteAddr) {
        return NULL;
    }
    SleSsapConnectDevNode_t *item = NULL;
    SleSsapConnectDevNode_t *target = NULL;
    pthread_mutex_lock(&g_mutex);
    LIST_FOR_EACH_ENTRY(item, &g_sleSsapConnectList, SleSsapConnectDevNode_t, node) {
        if (0 == memcmp(item->addr.addr, remoteAddr->addr, SLE_DEVICE_ADDRESS_LEN)) {
            target = item;
            break;
        }
    }
    pthread_mutex_unlock(&g_mutex);
    return target;
}

static SleSsapConnectDevNode_t *GetSsapConnNodeByConnId(uint16_t connectId)
{
    SleSsapConnectDevNode_t *item = NULL;
    SleSsapConnectDevNode_t *target = NULL;
    pthread_mutex_lock(&g_mutex);
    LIST_FOR_EACH_ENTRY(item, &g_sleSsapConnectList, SleSsapConnectDevNode_t, node) {
        if (item->connectId == connectId) {
            target = item;
            break;
        }
    }
    pthread_mutex_unlock(&g_mutex);
    return target;
}

static SleSsapConnectDevNode_t *GetSsapConnectReadyNode(const SleDeviceAddress *addr, const uint16_t *pConnId)
{
    if (addr == NULL && pConnId == NULL) {
        SLE_LOGE("%s: param invalid. Error.", __func__);
        return NULL;
    }
    SleSsapConnectDevNode_t *item = NULL;
    if (addr) {
        item = GetSsapConnNodeByAddr(addr);
    } else if (pConnId) {
        item = GetSsapConnNodeByConnId(*pConnId);
    }
    
    if (item == NULL) {
        SLE_LOGE("%s: Please establish a connection to dev(%02x:%02x:%02x:%02x:%02x:%02x) first. Error.", __func__,
                addr->addr[0], addr->addr[1], addr->addr[2], addr->addr[3], addr->addr[4], addr->addr[5]);
        return NULL;
    }
    if (item->connState != SLE_SSAP_CONNECT_STATE_INFO_EXCHANGED) {
        SLE_LOGE("%s: Connect state isn't ready. Please retry establish a connection later. Error.", __func__);
        return NULL;
    }
    return item;
}

static SleSsapConnectDevNode_t *InsertNewSleSsapConnectDevNode(const SleDeviceAddress *addr)
{
    SleSsapConnectDevNode_t *node = (SleSsapConnectDevNode_t *)calloc(1, sizeof(SleSsapConnectDevNode_t));
    if (node == NULL) {
        SLE_LOGE("%s: calloc failed. Error.", __func__);
        return NULL;
    }
    pthread_mutex_lock(&g_mutex);
    ListInit(&node->node);
    ListTailInsert(&g_sleSsapConnectList, &node->node);
    node->connectId = INVALID_CONNECT_ID;
    if (addr) {
        memcpy(&node->addr, addr, sizeof(SleDeviceAddress));
    }
    pthread_mutex_unlock(&g_mutex);
    return node;
}

static void SetSsapConnDevInfoLinkConnected(uint16_t connectId, const SleDeviceAddress *addr)
{
    pthread_mutex_lock(&g_mutex);
    SleSsapConnectDevNode_t *item = GetSsapConnNodeByAddr(addr);
    if (item == NULL) {
        SLE_LOGI("%s: can't found target dev node in global_list", __func__);
        item = InsertNewSleSsapConnectDevNode(addr);
        if (item == NULL) {
            SLE_LOGE("%s: do InsertNewSleSsapConnectDevNode failed. Error.", __func__);
            return;
        }
    }
    item->connState = SLE_SSAP_CONNECT_STATE_LINK_CONNECTED;
    item->connectId = connectId;
    pthread_mutex_unlock(&g_mutex);
    SLE_LOGI("%s: found node localRole=%u", __func__, item->localRole);
    if (item->localRole == SLE_SSAP_ROLE_IS_CLIENT) {
        SleConnectionParamUpdate param;
        param.connectId = connectId;
        param.intervalMin = g_sleConnParam.interval;
        param.intervalMax = g_sleConnParam.interval;
        param.maxLatency  = g_sleConnParam.latency;
        param.supervisionTimeout = g_sleConnParam.supervisionTimeout;
        if (SLE_NO_ERROR != SleUpdateConnParam(&param)) {
            item->connState = SLE_SSAP_CONNECT_STATE_ERROR;
            SLE_LOGE("%s: ssapClient do SleUpdateConnParam failed. Error.", __func__);
        }
        SLE_LOGI("%s: ssapClient do SleUpdateConnParam success", __func__);
    }
}

static void SleHostStateChangeCallbackInner(SleDeviceState state)
{
    if (state == SLE_HOST_STATE_DISABLED) {
        ClearSleSsapConnectList();
    }
}

static SleHostCallbacks g_iperfToolHostCbs = {
    .OnSleHostStateChangeCb = SleHostStateChangeCallbackInner,
};

static void SleConnectStateChangeCallbackInner(uint16_t connectId, const SleDeviceAddress *addr,
                    SleConnectState connState, SlePairState pairState, SleDisConnectReason discReason)
{
    SLE_TEST_TOOL_LOG("[%s] connectId = %d, addr = "MACSTR", connState = %s(%d), pairState = %s(%d), discReason = %s(%hhu)\n", __func__,
        connectId, MAC2STR(addr->addr), SleConnectStateStr(connState), connState, SlePairStateStr(pairState), pairState, SleDisConnectReasonStr(discReason), discReason);
    if (connState == SLE_CONNECT_DISCONNECTED_STATE) {
        DeleteSsapConnDevNodeBySleAddr(addr);
    } else if (connState == SLE_CONNECT_CONNECTED_STATE) {
        SetSsapConnDevInfoLinkConnected(connectId, addr);
    }
}

static void SleConnParamUpdatedCallbackInner(uint16_t connectId, SleErrorCode errCode, 
                                    const SleConnectionParamUpdateEvt *connParam)
{
    SLE_TEST_TOOL_LOG("[%s] connectId = %d, errCode = %hhu, connInterval = %d, connLatency = %d, connTimeout = %d\n",
            __func__, connectId, errCode, connParam->interval, connParam->latency, connParam->supervisionTimeout);
    SleSsapConnectDevNode_t *item = GetSsapConnNodeByConnId(connectId);
    if (item == NULL) {
        SLE_LOGE("%s: can't find connect node by connectId %hu. Error.", __func__, connectId);
        return;
    }
    if (item->connState == SLE_SSAP_CONNECT_STATE_ERROR) {
        SLE_LOGI("%s: connectId = %hu, found state error. Disconnect this connection.", __func__, connectId);
        SleDisconnect(&item->addr);
        return;
    }
    item->connState = SLE_SSAP_CONNECT_STATE_CONN_PARAM_UPDATED;
    if (item->localRole == SLE_SSAP_ROLE_IS_CLIENT) {
        if (0xFF == GetSleToolSsapClientId()) {
            SLE_LOGE("%s: ssap client unInit. Error.", __func__);
            SleDisconnect(&item->addr);
            return;
        }
        SsapMtuInfo paramExchange = {
            .mtuSize = HI3863_MAX_MTU,
            .version = HI3863_MTU_VERSION,
        };
        SleErrorCode ret = SendExchangeInfoReq(GetSleToolSsapClientId(), connectId, &paramExchange);
        if (ret != SLE_NO_ERROR) {
            item->connState = SLE_SSAP_CONNECT_STATE_ERROR;
            SLE_LOGE("%s: ssapClient do SendExchangeInfoReq failed. Error.", __func__);
            SleDisconnect(&item->addr);
        }
    }
}

static SleConnectCallbacks g_iperfToolConnectCbs = {
    .OnSleConnStateChangeCb = SleConnectStateChangeCallbackInner,
    .OnSleConnParamUpdatedCb = SleConnParamUpdatedCallbackInner,
};

void SleExchangeMtuInfoSsapsCallbackInner(SleErrorCode errCode, uint8_t serverId, uint16_t connectId, const SsapMtuInfo *mtuInfo)
{
    SLE_LOGI("%s: connectId = %hu. serverId = %u, mtuInfo=%u.", __func__, connectId, serverId, mtuInfo?(mtuInfo->mtuSize):0);
    SleSsapConnectDevNode_t *item = GetSsapConnNodeByConnId(connectId);
    if (item == NULL) {
        SLE_LOGE("%s: can't find connect node by connectId %hu. Error.", __func__, connectId);
        return;
    }
    if (item->localRole != SLE_SSAP_ROLE_IS_SERVER) {
        SLE_LOGE("%s: connectId = %hu, found node role is client, unmatch. Error.", __func__, connectId);
        return;
    }
    item->connState = SLE_SSAP_CONNECT_STATE_INFO_EXCHANGED;
}

void SleRequestWriteCallbackInner(SleErrorCode errCode, uint8_t serverId, uint16_t connectId, const SsapsReqWriteCbPara *writeCbPara)
{
    CHECK_NULL_PTR_RETURN_VOID(writeCbPara);
    sle_kht_msghdr *msghdr = (sle_kht_msghdr *)writeCbPara->value;
    if (msghdr->magic_num != SLE_KHT_MAGIC_NUM) {
        printf("[%s] serverId=%hhu, connectId=%hu, handle=%hu, type=%hhu. \r\n", __func__, serverId, connectId, writeCbPara->handle,writeCbPara->type);
        return;
    }
    switch(msghdr->msgid) {
        case MSG_ID_LONG_TERM_STABILITY_TEST:
            if (writeCbPara->valueLen < sizeof(sle_kht_msghdr)) {
                printf("[%s] long term stability test recv data len unmatch. Error. \r\n", __func__);
                return;
            }
            SsapsNotifyParam param = {0};
            param.handle = 1;
            param.type = SSAP_PROPERTY_TYPE_VALUE_TYPE;
            param.valueLen = writeCbPara->valueLen;
            param.value = msghdr;

            SleErrorCode ret = NotifyIndicate(serverId, connectId, &param);
            if(ret != SLE_NO_ERROR) {
                printf("[%s] NotifyIndicate failed(%hhu). Error.\r\n", __func__, ret);
            }
            break;
        default:
            break;
    }
}

static SleSsapsCallbacks g_iperfToolSsapsCbs = {
    .OnChangeMtuCb = SleExchangeMtuInfoSsapsCallbackInner,
    .OnRequestWriteCb = SleRequestWriteCallbackInner,
};

static void SleExchangeInfoSsapcCallbackInner(uint8_t clientId, uint16_t connectId
        , const SsapMtuInfo *exchangeInfo, SleErrorCode errCode)
{
    SLE_LOGI("%s: connectId = %hu. clientId, mtuInfo=%u.", __func__, connectId, clientId, exchangeInfo?(exchangeInfo->mtuSize):0);
    SleSsapConnectDevNode_t *item = GetSsapConnNodeByConnId(connectId);
    if (item == NULL) {
        SLE_LOGE("%s: can't find connect node by connectId %hu. Error.", __func__, connectId);
        return;
    }
    if (item->localRole != SLE_SSAP_ROLE_IS_CLIENT) {
        SLE_LOGE("%s: connectId = %hu, found node role is ssapServer, unmatch. Error.", __func__, connectId);
        return;
    }
    item->connState = SLE_SSAP_CONNECT_STATE_INFO_EXCHANGED;
}

static double CalcTransferRateOfMbps(uint64_t sumBytes, uint64_t sumMicroseconds)
{
    double rate_iperf = 0;
    if(!sumBytes|!sumMicroseconds){
        return rate_iperf;
    }
    double mSeconds = sumMicroseconds/1000;
    rate_iperf = (double)((sumBytes*8*1000)/mSeconds);
    rate_iperf = rate_iperf/1000/1000; // Mbps.
    return rate_iperf;
}

static void SleServerThroughputTestCalc(sle_kht_msghdr *msghdr, SleSsapConnectDevNode_t *item, ClientHandleValue *data)
{
    if (!msghdr || !item || !data) {
        SLE_LOGE("%s: param invalid. Error.", __func__);
        return;
    }
    if (item->serverThroughputTestInfo == NULL) {
        SLE_LOGI("%s: serverThroughputTestInfo not ready.", __func__);
        return;
    }
    char buf[2][10] = {0};
    double rate_iperf = 0;
    SleThroughputTestInfo_t *info = item->serverThroughputTestInfo;
    switch (msghdr->msgid) {
        case SLE_KHT_COMM_RX_PAYLOAD:
            // 统计流量
            if (0 == info->ssap_rx_stat.total_count) {
                info->ssap_rx_stat.begin_tv_us = sle_khtest_clock_gettime_us_lite();
                info->ssap_rx_stat.total_drops = 0;
                //info->ssap_rx_stat.seq_start = msghdr->seqid;
                //info->ssap_rx_stat.seq_stop = info->ssap_rx_stat.seq_start;
                info->ssap_rx_stat.total_bytes = data->dataLength;
                info->sle_kht_this_pack_arrive = info->ssap_rx_stat.begin_tv_us;
                info->sle_kht_last_pack_arrive = info->sle_kht_this_pack_arrive;
                info->sle_kht_max_jitter = 0;
            } else {
                //info->ssap_rx_stat.seq_stop = msghdr->seqid;
                info->ssap_rx_stat.total_bytes += data->dataLength;
                info->sle_kht_this_pack_arrive = sle_khtest_clock_gettime_us_lite();
                uint64_t diff_jitter = info->sle_kht_this_pack_arrive - info->sle_kht_last_pack_arrive;
                info->sle_kht_max_jitter = (info->sle_kht_max_jitter > diff_jitter)?info->sle_kht_max_jitter:diff_jitter;
                info->sle_kht_last_pack_arrive = info->sle_kht_this_pack_arrive;
            }

            if (info->start_seq == 0) {
                info->start_seq = msghdr->seqid; // 记录本轮统计第一个包的序列号
                info->last_seq = msghdr->seqid;
            } else {
                do {
                    if (msghdr->seqid < info->start_seq) {
                        break; // 旧的报文
                    }

                    //msghdr->seqid > info->start_seq
                    if (msghdr->seqid > info->last_seq) {
                        if ((msghdr->seqid - info->last_seq) > 1) {
                            // 乱序丢包
                            info->ssap_rx_stat.total_drops += (msghdr->seqid - info->last_seq - 1);
                        }
                        info->last_seq = msghdr->seqid;
                        break;
                    }

                    if (msghdr->seqid == info->last_seq) {
                        // pthread_mutex_unlock(&tx_mutex);
                        return; // 重复的包
                    }

                    if (msghdr->seqid < info->last_seq) {
                        // 前面的乱序包, 补偿
                        if (info->ssap_rx_stat.total_drops > 0) {
                            info->ssap_rx_stat.total_drops --;
                        }
                    }
                } while (0);
            }

            info->ssap_rx_stat.total_count += 1;
            // printf("[iperf-test] seqid: %d, data->dataLength: %d\r\n", msghdr->seqid, data->dataLength);
            if ((info->ssap_rx_stat.total_count + info->ssap_rx_stat.total_drops) >= info->g_SLE_KHT_IPERF_ONCE_PACK_NUM_S_TO_C) {
                info->ssap_rx_stat.end_tv_us = sle_khtest_clock_gettime_us_lite();
                uint64_t costTime = info->ssap_rx_stat.end_tv_us - info->ssap_rx_stat.begin_tv_us;
                rate_iperf = CalcTransferRateOfMbps(info->ssap_rx_stat.total_bytes, costTime);
                printf("[iperf-test] one_pack_size: %d, rate_iperf: %sMbps, cost_time_ms: %sms, "
                       "this_drop %u, this_receive %u, this_pack %u\r\n", data->dataLength, 
                       DoubleToString(rate_iperf, buf[0], sizeof(buf[0])), DoubleToString(costTime/1000.0, buf[1], sizeof(buf[1])),
                       info->ssap_rx_stat.total_drops, info->ssap_rx_stat.total_count,
                       (info->ssap_rx_stat.total_drops + info->ssap_rx_stat.total_count));
                info->recvSumBytes += info->ssap_rx_stat.total_bytes;
                info->recvCostSumMicroseconds += costTime;
                info->ssap_rx_stat.total_count = 0;
                info->ssap_rx_stat.total_bytes = 0;
                info->ssap_rx_stat.total_drops = 0;
            }
            break;
        case SLE_KHT_COMM_RX_END:
            printf("[iperf-test] recerve end.\r\n");
            rate_iperf = CalcTransferRateOfMbps(info->recvSumBytes, info->recvCostSumMicroseconds);
            printf("[iperf-test] Throughput test summary: rate_iperf = %sMbps. \r\n", DoubleToString(rate_iperf, buf[0], sizeof(buf[0])));
            if (info) {
                free(info);
                info = NULL;
            }
            break;
        default:
            break;
    }
}

static void SleLatencyTestCalc(SleSsapConnectDevNode_t *item, uint8_t clientId, const ClientHandleValue *data)
{
    CHECK_NULL_PTR_RETURN_VOID(item);
    CHECK_NULL_PTR_RETURN_VOID(data);
    if (item->latencyTestInfo == NULL) {
        printf("[iperf-test] get sle latency test param failed. Error.\r\n");
        return;
    }
    uint64_t recvEchoMsgTime = sle_khtest_clock_gettime_us_lite();
    uint64_t lastLoopTestTime = recvEchoMsgTime - item->latencyTestInfo->lastSendTime; //本次包时延
    item->latencyTestInfo->delayTimeSum += lastLoopTestTime;    // 总计时延
    item->latencyTestInfo->cycleCount++;
    if (item->latencyTestInfo->cycleCount == 1) {
        item->latencyTestInfo->oneCycleMaxTime = lastLoopTestTime;
        item->latencyTestInfo->oneCycleMinTime = lastLoopTestTime;
    } else {
        item->latencyTestInfo->oneCycleMaxTime = 
            (item->latencyTestInfo->oneCycleMaxTime > lastLoopTestTime)?(item->latencyTestInfo->oneCycleMaxTime):lastLoopTestTime;
        item->latencyTestInfo->oneCycleMinTime = 
            (item->latencyTestInfo->oneCycleMinTime < lastLoopTestTime)?(item->latencyTestInfo->oneCycleMinTime):lastLoopTestTime;
    }
    
    printf("[iperf-test] receive NO.%u package, time_delay: %"PRIu64"us \r\n",
                item->latencyTestInfo->cycleCount, lastLoopTestTime);
    if ((item->latencyTestInfo->endTime && (recvEchoMsgTime >= item->latencyTestInfo->endTime)) ||
        (item->latencyTestInfo->sendPackageSum && (item->latencyTestInfo->sendPackageSum <= item->latencyTestInfo->cycleCount))) {
        printf("[iperf-test][delay test end] cycleCount = %u, one_cycle_avarage = %"PRIu64"us, one_cycle_time_range: [%"PRIu64", %"PRIu64"], delay_jitter:%"PRIu64"us. \r\n",
            item->latencyTestInfo->cycleCount, (item->latencyTestInfo->delayTimeSum / item->latencyTestInfo->cycleCount),
            item->latencyTestInfo->oneCycleMinTime, item->latencyTestInfo->oneCycleMaxTime, 
            item->latencyTestInfo->oneCycleMaxTime - item->latencyTestInfo->oneCycleMinTime);
            free(item->latencyTestInfo);
            item->latencyTestInfo = NULL;
        return;
    }

    ClientWriteParam paramWrite;
    paramWrite.handle = data->handle;
    paramWrite.type = data->type;
    paramWrite.dataLength = sizeof(sle_kht_msghdr);
    paramWrite.data = (uint8_t*)calloc(1, sizeof(sle_kht_msghdr));
    if (paramWrite.data == NULL) {
        SLE_LOGE("%s: latencyTestInfo paramWrite do calloc failed. Error.", __func__);
        return;
    }
    sle_kht_msghdr *msghdr = (sle_kht_msghdr *)paramWrite.data;
    msghdr->msgid = COUNT_TIME_DELAY_ID;
    msghdr->magic_num = SLE_KHT_MAGIC_NUM;
    msghdr->length = paramWrite.dataLength;

    usleep(item->latencyTestInfo->interval * 1000);
    item->latencyTestInfo->lastSendTime = sle_khtest_clock_gettime_us_lite();
    uint16_t connectId = item->connectId;
    uint8_t ssapClientId = GetSleToolSsapClientId();
    SleErrorCode ret = SendWriteCmd(ssapClientId, connectId, &paramWrite);

    if(ret != SLE_NO_ERROR) {
        SLE_LOGE("%s: SendWriteCmd failed(%hhu). Error.", __func__, ret);
    }
    free(paramWrite.data);
}

static void SleStabilityTestCalc(sle_kht_msghdr *msghdr, SleSsapConnectDevNode_t *item)
{
    CHECK_NULL_PTR_RETURN_VOID(msghdr);
    CHECK_NULL_PTR_RETURN_VOID(item);
    CHECK_NULL_PTR_RETURN_VOID(item->ltsTestInfo)
    
    if (KHCMutexLockRecursive(&mkhMutex) != 0) {
        printf("[%s_%d] KHCMutexLockRecursive failed. Error.\n", __func__, __LINE__);
        return;
    }
    if (item->ltsTestInfo) {
        item->ltsTestInfo->recvSeqId = msghdr->seqid;
        item->ltsTestInfo->cycleRecvTime = sle_khtest_clock_gettime_us_lite();
    }
    if (KHCMutexUnlockRecursive(&mkhMutex) != 0) {
        printf("[%s_%d] KHCMutexUnlockRecursive failed. Error.\n", __func__, __LINE__);
    }
    if (KHCConditionSingnal(&mkhMutexCond) != 0) {
        printf("[%s] KHCConditionSingnal failed. Error.\n", __func__);
    }
}

static void SleNotificatedSsapcCallbackInner(uint8_t clientId, uint16_t connectId,
                                const ClientHandleValue *data, SleErrorCode errCode)
{
    CHECK_NULL_PTR_RETURN_VOID(data);
    if (data->dataLength < sizeof(sle_kht_msghdr)) {
        printf("[SleSsapClientTestTool] OnSleTNotificatedCb: (%d,%d) handle(%d) type(%s) errCode(%hhu) value(%s). Recv data len unmatch. Error.\r\n"
                , connectId, clientId, data->handle, SleSsapPropertyTypeStr(data->type), errCode, data->data);
        return;
    }
    sle_kht_msghdr *msghdr = (sle_kht_msghdr *)data->data;
    if (msghdr->magic_num != SLE_KHT_MAGIC_NUM) {
        printf("[SleSsapClientTestTool] OnSleTNotificatedCb: (%d,%d) handle(%d) type(%s) errCode(%hhu) value(%s). Recv data context unknow. Error.\r\n"
                , connectId, clientId, data->handle, SleSsapPropertyTypeStr(data->type), errCode, data->data);
        return;
    }
    SleSsapConnectDevNode_t *item = GetSsapConnectReadyNode(NULL, &connectId);
    if (item == NULL) {
        SLE_LOGE("%s: get targetAddr dev connection id failed. Error.", __func__);
        return;
    }
    switch(msghdr->msgid) {
        case SLE_KHT_COMM_RX_PAYLOAD:
        case SLE_KHT_COMM_RX_END:
            SleServerThroughputTestCalc(msghdr, item, data);// data from ssaps send to ssapc
            break;
        case COUNT_TIME_DELAY_ID:
            SleLatencyTestCalc(item, clientId, data);
            break;
        case MSG_ID_LONG_TERM_STABILITY_TEST:
            SleStabilityTestCalc(msghdr, item);
            break;
        default:
            break;
    }
}

static SleSsapcCallbacks g_iperfToolSsapcCbs = {
    .OnSleExchangeInfoCb = SleExchangeInfoSsapcCallbackInner,
    .OnSleNotificatedCb = SleNotificatedSsapcCallbackInner,
};

SleErrorCode SleSsapConnectRemoteSsapServer(const SleDeviceAddress *addr)
{
    if (addr == NULL) {
        SLE_LOGE("%s: invalid remote address.", __func__);
        return SLE_ERR_INVALID_PARAM;
    }
    if (0xFF == GetSleToolSsapClientId()) {
        TAddSspaClient();
    }
    SleErrorCode ret;
    SleSsapConnectDevNode_t *item = GetSsapConnNodeByAddr(addr);
    if (item) {
        if (item->connState == SLE_SSAP_CONNECT_STATE_ERROR) {
            if (SLE_NO_ERROR != SleDisconnect(addr)) {
                SLE_LOGE("%s: SleDisconnect failed. Error. Please retry.", __func__);
                return SLE_ERR_UNKNOWN;
            }
           SLE_LOGI("%s: success clean old wrong state connection", __func__);
        } else {
            SLE_LOGI("Sle ssap connect remote dev addr[%02x:%02x:%02x:%02x:%02x:%02x] successfully.",
                    addr->addr[0], addr->addr[1], addr->addr[2], addr->addr[3], addr->addr[4], addr->addr[5]);
            return SLE_NO_ERROR;
        }
    }
    item = InsertNewSleSsapConnectDevNode(addr);
    item->localRole = SLE_SSAP_ROLE_IS_CLIENT;
    ret = SleConnect(addr);
    if (ret != SLE_NO_ERROR) {
        SLE_LOGE("%s: SleConnect failed. Error.", __func__);
        DelSsapConnDevNode(item);
    }
    return ret;
}

static SleErrorCode SleSsapConnectModuleInit(void)
{
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);

    if(pthread_mutex_init(&g_mutex, &attr) != 0) {
        printf("[%s]: pthread_mutex_init failed. Error.\n", __func__);
        return SLE_ERR_FAILED;
    }
    if(KHCMutexCreateRecursive(&mkhMutex) != 0) {
        printf("[%s]: KHCMutexCreateRecursive failed. Error.\n", __func__);
        pthread_mutex_destroy(&g_mutex);
        return SLE_ERR_FAILED;
    }
    if (KHCConditionInit(&mkhMutexCond, NULL) != 0) {
        printf("[%s]: KHCConditionInit failed. Error.\n", __func__);
        KHCMutexDelete(&mkhMutex);
        pthread_mutex_destroy(&g_mutex);
        return SLE_ERR_FAILED;
    }

    return SLE_NO_ERROR;
}

SleErrorCode RegisterSleIperfToolCbs(void)
{
    if (SLE_NO_ERROR != SleSsapConnectModuleInit()) {
        SLE_LOGE("[%s] SleSsapConnectModuleInit failed. Error.", __func__);
        return SLE_ERR_UNKNOWN;
    }

    SleErrorCode ret = SLE_ERR_UNKNOWN;
    ret = RegisterHostCallbacks(&g_iperfToolHostCbs);
    if (SLE_NO_ERROR != ret)
    {
        SLE_LOGE("[%s] RegisterHostCallbacks failed. ret = %d", __func__, ret);
        return ret;
    }

    ret = RegisterConnectCallbacks(&g_iperfToolConnectCbs);
    if (SLE_NO_ERROR != ret)
    {
        SLE_LOGE("[%s] RegisterConnectCallbacks failed. ret = %d", __func__, ret);
        return ret;
    }

    ret = RegisterSsapServerCallbacks(&g_iperfToolSsapsCbs);
    if (SLE_NO_ERROR != ret)
    {
        SLE_LOGE("[%s] RegisterSsapServerCallbacks failed. ret = %d", __func__, ret);
        return ret;
    }
    
    ret = RegisterSsapClientCallbacks(&g_iperfToolSsapcCbs);
    if (SLE_NO_ERROR != ret)
    {
        SLE_LOGE("[%s] RegisterSsapClientCallbacks failed. ret = %d", __func__, ret);
        return ret;
    }
    SLE_LOGI("[%s] sle ssap iperf tool init success.", __func__);
    return SLE_NO_ERROR;
}

void SleThroughputSsapsTest(SleDeviceAddress *targetAddr, int32_t testSeconds, int32_t sendPackageSum)
{
    if (!targetAddr) {
        SLE_LOGE("%s: targetAddr param invalid. Error.", __func__);
        return;
    }

    SleSsapConnectDevNode_t *item = GetSsapConnectReadyNode(targetAddr, NULL);
    if (item == NULL) {
        SLE_LOGE("%s: get targetAddr dev connection id failed. Please do ssap connect first. Error.", __func__);
        return;
    }
    if (item->serverThroughputTestInfo) {
        SLE_LOGI("%s: Busy, targetAddr dev has already been in client throughput test. Please wait last cmd test complete.", __func__);
        return;
    }

    item->serverThroughputTestInfo = (SleThroughputTestInfo_t *)calloc(1, sizeof(SleThroughputTestInfo_t));
    if (item->serverThroughputTestInfo == NULL) {
        SLE_LOGE("%s: serverThroughputTestInfo do calloc failed. Error.", __func__);
        return;
    }
    if (!testSeconds && !sendPackageSum) {
        sendPackageSum = THROUGHPUT_TEST_PACKAGE_SUM_DEFAULT;
    }
    item->serverThroughputTestInfo->g_ALL_SEND_PACKAGE_S_TO_C = 1000;
    item->serverThroughputTestInfo->g_SEND_STEP_S_TO_C = 
                    sendPackageSum /(item->serverThroughputTestInfo->g_ALL_SEND_PACKAGE_S_TO_C);
    item->serverThroughputTestInfo->g_IPERF_TIME_S_TO_C = testSeconds;
    item->serverThroughputTestInfo->g_SLE_KHT_IPERF_ONCE_PACK_NUM_S_TO_C = 100;
    item->serverThroughputTestInfo->g_iperf_long_time_delay_msS_TO_C = 0;

    SLE_LOGI("%s: Get targetAddr[%02x:%02x:%02x:%02x:%02x:%02x], testSeconds[%d], sendPackageSum[%d]", __func__,
        targetAddr->addr[0],targetAddr->addr[1],targetAddr->addr[2],targetAddr->addr[3],targetAddr->addr[4],targetAddr->addr[5],
        testSeconds, sendPackageSum);
    int32_t mySendSize = HI3863_SEND_MAX_DATA_LEN;
    int32_t size_send = HI3863_SEND_MAX_DATA_LEN;

    ClientWriteParam paramWrite = {0};
    paramWrite.handle = 2;
    paramWrite.type = SLE_SSAP_PROPERTY_TYPE;
    paramWrite.dataLength = mySendSize;

    uint8_t *data = calloc(paramWrite.dataLength, sizeof(uint8_t));
    if (data == NULL) {
        printf("%s: Failed to allocate memory. Error.\n",__func__);
        return;
    }
    paramWrite.data = data;

    sle_kht_msghdr *msghdr = (sle_kht_msghdr *)data;
    msghdr->msgid = SLE_KHT_COMM_CLIENT_REQ_SERVER;
    msghdr->magic_num = SLE_KHT_MAGIC_NUM;
    msghdr->seqid = 0;
    msghdr->length = size_send;
    msghdr->sendstep = item->serverThroughputTestInfo->g_SEND_STEP_S_TO_C;
    msghdr->allsendpackage = item->serverThroughputTestInfo->g_ALL_SEND_PACKAGE_S_TO_C;
    msghdr->oncecount = item->serverThroughputTestInfo->g_SLE_KHT_IPERF_ONCE_PACK_NUM_S_TO_C;
    msghdr->iperftime = item->serverThroughputTestInfo->g_IPERF_TIME_S_TO_C;
    msghdr->iperfdelaytime = item->serverThroughputTestInfo->g_iperf_long_time_delay_msS_TO_C;

    uint16_t connectId = item->connectId;
    uint8_t ssapClientId = GetSleToolSsapClientId();
    SleErrorCode ret = SendWriteCmd(ssapClientId, connectId, &paramWrite);
    if (ret != SLE_NO_ERROR) {
        printf("[%s] SendWriteCmd failed(%hhu), connectId: %d\r\n", __func__, ret, connectId);
        free(item->serverThroughputTestInfo);
        item->serverThroughputTestInfo = NULL;
    } else {
        printf("[%s] SendWriteCmd ok, connectId: %d\r\n", __func__, connectId);
    }
}

void SleLatencySsapcTest(SleDeviceAddress *remoteAddr, int32_t durationSeconds, int32_t sendPkgSum, int32_t sendInterval)
{
    SleSsapConnectDevNode_t *item = GetSsapConnectReadyNode(remoteAddr, NULL);
    if (item == NULL) {
        SLE_LOGE("%s: get targetAddr dev connection id failed. Please do ssap connect first. Error.", __func__);
        return;
    }
    if (item->latencyTestInfo) {
        SLE_LOGI("%s: Busy, targetAddr dev already being tested. Please wait last cmd test complete.", __func__);
        return;
    }
    item->latencyTestInfo = (SleLatencyTestInfo_t*)calloc(1, sizeof(SleLatencyTestInfo_t));
    if (item->latencyTestInfo == NULL) {
        SLE_LOGE("%s: latencyTestInfo do calloc failed. Error.", __func__);
        return;
    }
    if (durationSeconds) {
        uint64_t mircoSecond = (uint64_t)durationSeconds;
        mircoSecond *= 1000000ULL;
        item->latencyTestInfo->endTime = sle_khtest_clock_gettime_us_lite() + mircoSecond;
    }
    item->latencyTestInfo->sendPackageSum = sendPkgSum;
    item->latencyTestInfo->interval = sendInterval;
    if (!sendPkgSum && !durationSeconds) {
        item->latencyTestInfo->sendPackageSum = LATENCY_TEST_SEND_TIMES_DEFAULT; 
    }
    if (!item->latencyTestInfo->interval) {
        item->latencyTestInfo->interval = LATENCY_TEST_SEND_INTERVAL_DEFAULT;
    }
    SLE_LOGI("%s: Get targetAddr[%02x:%02x:%02x:%02x:%02x:%02x], sendInterval=%dms, sendPackageSum=%d, testSeconds=%ds, ", __func__,
        remoteAddr->addr[0],remoteAddr->addr[1],remoteAddr->addr[2],remoteAddr->addr[3],remoteAddr->addr[4],remoteAddr->addr[5],
        item->latencyTestInfo->interval, item->latencyTestInfo->sendPackageSum, durationSeconds);
    ClientWriteParam paramWrite;
    paramWrite.handle = 2;
    paramWrite.type = SLE_SSAP_PROPERTY_TYPE;
    paramWrite.dataLength = sizeof(sle_kht_msghdr);
    paramWrite.data = (uint8_t*)calloc(1, sizeof(sle_kht_msghdr));
    if (paramWrite.data == NULL) {
        SLE_LOGE("%s: latencyTestInfo paramWrite do calloc failed. Error.", __func__);
        return;
    }
    sle_kht_msghdr *msghdr = (sle_kht_msghdr *)paramWrite.data;
    msghdr->msgid = COUNT_TIME_DELAY_ID;
    msghdr->magic_num = SLE_KHT_MAGIC_NUM;
    msghdr->length = paramWrite.dataLength;
    
    uint16_t connectId = item->connectId;
    uint8_t ssapClientId = GetSleToolSsapClientId();
    item->latencyTestInfo->lastSendTime = sle_khtest_clock_gettime_us_lite();
    SleErrorCode ret = SendWriteCmd(ssapClientId, connectId, &paramWrite);

    if(ret != SLE_NO_ERROR) {
        printf("[SleLatencySsapcTest] SendWriteCmd failed(%hhu). Error.\r\n", ret);
    }
    free(paramWrite.data);
}

static void SleStabilityTestThread(void *arg)
{
    SleSsapConnectDevNode_t *item = (SleSsapConnectDevNode_t *)arg;
    uint64_t currentTime = 0;
    uint64_t oneCycleRTT = 0;
    uint64_t testSumSeconds = 0;
    double rate = 0;
    char buf[10] = {0};
    if (item == NULL) {
        SLE_LOGE("%s: get targetAddr dev connection id failed. Please do ssap connect first. Error.", __func__);
        return;
    }
    if (item->ltsTestInfo == NULL) {
        SLE_LOGI("%s: found test param is NULL. Error.", __func__);
        return;
    }
    SleDeviceAddress *remoteAddr = &item->addr;
    printf("[%s] devAddr=%02x:%02x:%02x:%02x:%02x:%02x, durationSeconds= %"PRIu64" seconds, sendPkgSum=%u, sendInterval=%u millisecond. \r\n",__func__,
        remoteAddr->addr[0],remoteAddr->addr[1],remoteAddr->addr[2],remoteAddr->addr[3],remoteAddr->addr[4],remoteAddr->addr[5],
        item->ltsTestInfo->endTime, item->ltsTestInfo->sendPackageSum, item->ltsTestInfo->interval);
    if (item->ltsTestInfo->endTime) {
        testSumSeconds = item->ltsTestInfo->endTime;
        item->ltsTestInfo->endTime *= 1000000;
        item->ltsTestInfo->endTime += sle_khtest_clock_gettime_us_lite();
    }
    
    sle_kht_msghdr *msghdr = (uint8_t*)calloc(1, sizeof(sle_kht_msghdr));
    if (!msghdr) {
        SLE_LOGE("%s: msghdr do calloc failed. Error.", __func__);
        if (item->ltsTestInfo) {
            free(item->ltsTestInfo);
            item->ltsTestInfo = NULL;
        }
        return;
    }
    item->ltsTestInfo->recvSeqId = 0xFFFFFFFF;
    item->ltsTestInfo->cycleLastPrintTime = sle_khtest_clock_gettime_us_lite();
    uint16_t connectId = item->connectId;
    uint8_t ssapClientId = GetSleToolSsapClientId();
    ClientWriteParam paramWrite;
    paramWrite.handle = 2;
    paramWrite.type = SLE_SSAP_PROPERTY_TYPE;
    paramWrite.dataLength = sizeof(sle_kht_msghdr);
    paramWrite.data = msghdr;
    while(1) {
        if (KHCMutexLockRecursive(&mkhMutex) != 0) {
            printf("[%s_%d] KHCMutexLockRecursive failed. Error.\n", __func__, __LINE__);
            break;
        }
        msghdr->msgid = MSG_ID_LONG_TERM_STABILITY_TEST;
        msghdr->magic_num = SLE_KHT_MAGIC_NUM;
        msghdr->length = paramWrite.dataLength;
        msghdr->seqid = item->ltsTestInfo->msgSeqId;
        item->ltsTestInfo->cycleSendTime = sle_khtest_clock_gettime_us_lite();
        SleErrorCode ret = SendWriteCmd(ssapClientId, connectId, &paramWrite);
        if(ret != SLE_NO_ERROR) {
            printf("[%s] SendWriteCmd failed(%hhu). Error.\r\n", __func__, ret);
            break;
        }
        KHC_time_t time = KHCGetSysTime();
        timespec tv;
        tv.tv_sec = time/1000;
        tv.tv_nsec = time*1000*1000;
        tv.tv_sec += SLE_RECV_ECHO_DATA_TIMEOUT_SECONDS_DEFAULT;
        int32_t res = KHCConditionTimedwait(&mkhMutexCond, &mkhMutex, &tv);
        if (res != 0 && res != ETIMEDOUT) {
            printf("[%s] KHCConditionTimedwait failed, result=%d. Error.\n", __func__, res);
        }
        if (item->ltsTestInfo->recvSeqId != item->ltsTestInfo->msgSeqId) {
            item->ltsTestInfo->lostPkgCountSum += 1;
            item->ltsTestInfo->cycleLostPkgCount += 1;
        } else {
            oneCycleRTT = item->ltsTestInfo->cycleRecvTime - item->ltsTestInfo->cycleSendTime;
            item->ltsTestInfo->cycleRttSum += oneCycleRTT;
        }
        item->ltsTestInfo->msgSeqId += 1;
        item->ltsTestInfo->cycleSendedPkgCount += 1;
        // printf("[%s-%d] sendPackageSum=%u, msgSeqId=%u, one_RTT = %"PRIu64"us.\n", 
        //         __func__,__LINE__,item->ltsTestInfo->sendPackageSum, item->ltsTestInfo->msgSeqId, oneCycleRTT);
        if (KHCMutexUnlockRecursive(&mkhMutex) != 0) {
            printf("[%s_%d] KHCMutexUnlockRecursive failed. Error.\n", __func__, __LINE__);
            break;
        }
        usleep(item->ltsTestInfo->interval * 1000);
        if (item->ltsTestInfo->interval >= 1000) {
            printf("[%s-%d] send msgSeqId=%u, one_RTT = %"PRIu64"us.\n", 
                    __func__,__LINE__, item->ltsTestInfo->msgSeqId, oneCycleRTT);
        }

        currentTime = sle_khtest_clock_gettime_us_lite();
        if ((currentTime - item->ltsTestInfo->cycleLastPrintTime) >= LONG_TERM_STABILITY_TEST_CALC_CYCLE_SECONDS*1000000UL) {
            rate = (item->ltsTestInfo->cycleLostPkgCount) * 100.0 / item->ltsTestInfo->cycleSendedPkgCount;
            uint32_t cycleRecvCount = item->ltsTestInfo->cycleSendedPkgCount - item->ltsTestInfo->cycleLostPkgCount;
            uint32_t cycleRttSum = item->ltsTestInfo->cycleRttSum;
            printf("\n[iperf-test] cycle Average_RTT=%uus, sendPackages=%u, recvPackages=%u, lostPackage=%u, Packet loss rate= %s%%.\n\n",
                cycleRecvCount?(cycleRttSum/cycleRecvCount):0, item->ltsTestInfo->cycleSendedPkgCount, cycleRecvCount,
                item->ltsTestInfo->cycleLostPkgCount, DoubleToString(rate, buf, sizeof(buf)));

            item->ltsTestInfo->cycleRttSum = 0;
            item->ltsTestInfo->cycleSendedPkgCount = 0;
            item->ltsTestInfo->cycleLostPkgCount = 0;
            item->ltsTestInfo->cycleLastPrintTime = currentTime;
        }

        if(item->ltsTestInfo->endTime) {
            if (currentTime > item->ltsTestInfo->endTime) {
                break;
            }
        }
        if (item->ltsTestInfo->sendPackageSum && (item->ltsTestInfo->sendPackageSum <= item->ltsTestInfo->msgSeqId)) {
            break;
        }
    }
    
    printf("[iperf-test] Long term stability test done. testTime=%"PRIu64"s, pkgSum=%u, interval=%ums \r\n", 
        testSumSeconds, item->ltsTestInfo->sendPackageSum, item->ltsTestInfo->interval);
    if (KHCMutexLockRecursive(&mkhMutex) != 0) {
        printf("[%s_%d] KHCMutexLockRecursive failed. Error.\n", __func__, __LINE__);
        free(msghdr);
        return;
    }
    rate =  item->ltsTestInfo->lostPkgCountSum*100.0/(item->ltsTestInfo->msgSeqId);
    printf("[iperf-test] summary sendPackageSum=%u, lostPackageSum=%u, Packet loss rate=%s%%.\r\n", 
            item->ltsTestInfo->msgSeqId, item->ltsTestInfo->lostPkgCountSum, DoubleToString(rate, buf, sizeof(buf)));
    if (item->ltsTestInfo) {
        free(item->ltsTestInfo);
        item->ltsTestInfo = NULL;
    }
    free(msghdr);
    if (KHCMutexUnlockRecursive(&mkhMutex) != 0) {
        printf("[%s_%d] KHCMutexUnlockRecursive failed. Error.\n", __func__, __LINE__);
    }
}

void SleStabilityTest(SleDeviceAddress *remoteAddr, int32_t durationSeconds, int32_t sendPkgSum, int32_t sendInterval)
{
    SleSsapConnectDevNode_t *item = GetSsapConnectReadyNode(remoteAddr, NULL);
    if (item == NULL) {
        SLE_LOGE("%s: get targetAddr dev connection id failed. Please do ssap connect first. Error.", __func__);
        return;
    }

    if (item->ltsTestInfo) {
        SLE_LOGI("%s: Busy, targetAddr dev already being tested. Please wait last cmd test complete.", __func__);
        return;
    }

    item->ltsTestInfo = (SleLongTermStabilityTestInfo_t*)calloc(1, sizeof(SleLongTermStabilityTestInfo_t));
    if (item->ltsTestInfo == NULL) {
        SLE_LOGE("%s: ltsTestInfo do calloc failed. Error.", __func__);
        return;
    }

    if (!durationSeconds && !sendPkgSum) {
        durationSeconds = LONG_TERM_STABILITY_TEST_TIMES_DEFAULT;
    }

    if (durationSeconds) {
        item->ltsTestInfo->endTime = durationSeconds;
    }

    item->ltsTestInfo->sendPackageSum = sendPkgSum;
    item->ltsTestInfo->interval = sendInterval;
    if (item->ltsTestInfo->interval == 0) {
        item->ltsTestInfo->interval = LONG_TERM_STABILITY_TEST_INTERVAL_DEFAULT;
    }

    osThreadAttr_t attr;
    attr.name = "SleStabilityTestThread";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 4;
    attr.priority = 15;
    osThreadId_t sleStabilityTestThreadId = osThreadNew((osThreadFunc_t)SleStabilityTestThread, item, &attr);
    if (sleStabilityTestThreadId == NULL) {
        printf("[iperf-test] start sle long term stability thread failed. Error.\r\n");
    }
}